<template>
  <!-- 滚动渐渐显示 -->
  <!-- 计算当前屏幕位置，展示对应元素 -->
  <div class='scrollDisplay'>
    <div class="displayWrap">
      <div class="displayItem" :id="[`displayItem${index}`]"
        :style="{ 'backgroundColor': `#${Math.random().toString().slice(2, 8)}` }" v-for="item, index in 20" :key="index">
      </div>
    </div>
  </div>
</template>
 
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

class ScrollDisplay {
  constructor(options) {
    this.elements = options.map(item => ({ id: item })); // 存储元素id对象
    this.scrollHandler = this.scrollHand.bind(this)(); // 闭包初始化
    this.initElementPosition(); // 初始化
    this.rollMonitor(); // 开启滚动
  }
  // 元素位置初始化
  initElementPosition() {
    this.elements.forEach(item => {
      item.position = this.getElementPosition(item.id)
    })
  }
  // 获取元素离窗口顶部距离
  getElementPosition(id) {
    // 获取到元素，拿到起rect矩形值，当前元素距离窗口顶部距离的位置，加上window.scrollY就是当前元素距离窗口顶部的距离
    var elAttr = document.getElementById(id).getBoundingClientRect();
    return elAttr.top + window.scrollY;
  }
  // 页面滚动时，更新元素位置状态-是否显示
  scrollHand() {
    let timer = null; // 定时器

    let throttle = () => {
      let windowPosition = window.scrollY;
      let windowInnerHeight = window.innerHeight;
      this.elements.forEach(item => {
        // 滚动条+窗口高度>元素位置，元素显示  0.7 取窗口70%的高度
        if (windowPosition + (windowInnerHeight * 0.7) > item.position) {
          document.getElementById(item.id).style.opacity = 1;
        }
      })
      timer = null;
    }
    // 节流每200s允许执行一次
    return () => {
      if (timer === null) {
        timer = setTimeout(throttle, 100);
      }
    }
  }
  // 滚动监听
  rollMonitor() {
    this.scrollHandler();
    window.addEventListener('scroll', this.scrollHandler);
  }
  // 移除滚动监听
  closeRollMonitor() {
    window.removeEventListener('scroll', this.scrollHandler);
  }
}

const scrollDisplay = ref(null);

onMounted(() => {
  scrollDisplay.value = new ScrollDisplay(new Array(20).fill().map((item, index) => `displayItem${index}`));
})

onBeforeUnmount(() => {
  scrollDisplay.value.closeRollMonitor(); // 移除滚动监听
})

</script>
<style lang='scss' scoped>
.scrollDisplay {
  width: 100%;

  .displayWrap {
    width: 60%;
    margin: 0 auto;

    .displayItem {
      width: 100%;
      height: 20vh;
      // TODO 长列表性能优化
      content-visibility: hidden;
      margin-bottom: 4vh;
      border-radius: 5px;
      opacity: 0;
      transition: opacity 1.5s;
    }

    .show {
      opacity: 1;
    }
  }
}
</style>